﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MessageCallAspect.Inspector.MessageSink;
using MessageCallAspect.Inspector;
using MessageCallAspect.Aspect.Cache;
using MessageCallAspect.Aspect.Log;
using System.ComponentModel.Design;
using Syk.Library.Extensions;
using Syk.Library.Cache;

namespace MessageCallAspect
{

    public class TargetInspectorPolicy : ITargetInspectorPolicy
    {
        public TargetInspectorPolicy()
        {
            SinkCreatorPredicate = GetSinkCreatorPredicate();
        }

        public static Func<IMessageSinkCreator, bool> GetSinkCreatorPredicate()
        {
            Func<IMessageSinkCreator, bool> predicate = sc =>
            {
                CacheAspectAttribute cacheAspectAttribute = sc as CacheAspectAttribute;
                if (cacheAspectAttribute != null)
                {
                    bool enableCaching = true;
#if DEBUG
                    enableCaching = false;
#endif


                    return enableCaching;
                }
                else
                {
                    return true;
                }
            };

            return predicate;
        }
        #region ITargetInspectorPolicy Members

        public Func<IMessageSinkCreator, bool> SinkCreatorPredicate { get; private set; }

        #endregion
    }


    public class ServiceInspectorsContext : IServiceProvider, IDisposable
    {

        #region fields

        private readonly List<IMessageSinkCreator> m_SharedMessageSinkCreators;
        private readonly ServiceContainer m_ServiceContainer;
        #endregion

        #region ctor

        public ServiceInspectorsContext()
        {
            m_ServiceContainer = new ServiceContainer();
            m_SharedMessageSinkCreators = InitializeSharedMessageSinkCreators();
            InitializeServices();
        }

        #endregion

        /// <summary>
        /// enableInspectors by default is true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="serviceInstance"></param>
        public virtual void AddService<T>(T serviceInstance)
            where T : class
        {
            AddService<T>(serviceInstance, true);
        }

        public virtual void AddService<T>(T serviceInstance, bool enableInspectors, params IMessageSinkCreator[] messageSinkCreators)
            where T : class
        {
            if (enableInspectors)
            {
                IEnumerable<IMessageSinkCreator> sharedMessageSinkCreators;
                if (messageSinkCreators != null)
                {
                    sharedMessageSinkCreators = m_SharedMessageSinkCreators.Union(messageSinkCreators);
                }
                else
                {
                    sharedMessageSinkCreators = m_SharedMessageSinkCreators;
                }
                m_ServiceContainer.AddService(typeof(T), (new TargetInspectorProxy<T>(serviceInstance, this, sharedMessageSinkCreators.ToArray()).TransparentProxy));
            }
            else
            {
                m_ServiceContainer.AddService(typeof(T), serviceInstance);
            }

        }


        protected virtual List<IMessageSinkCreator> InitializeSharedMessageSinkCreators()
        {
            return new List<IMessageSinkCreator> 
            {
                new LogMessageSinkCreator{ Order = int.MinValue}
            };
        }

        protected virtual void InitializeServices()
        {
            MemoryCacheProvider cacheProvider = new MemoryCacheProvider { AllowActiveClearItemsScheduler = true };
            this.AddService<ICacheProvider>(cacheProvider, false);
            this.AddService<ITargetInspectorPolicy>(new TargetInspectorPolicy(), false);
        }

        #region IServiceProvider Members

        public object GetService(Type serviceType)
        {
            return m_ServiceContainer.GetService(serviceType);
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            m_ServiceContainer.Dispose();
        }

        #endregion
    }
}
